package com.lxw.manager.cms.service;

import com.alibaba.fastjson.JSON;
import com.lxw.framework.domain.cms.CmsPage;
import com.lxw.framework.domain.cms.CmsSite;
import com.lxw.framework.domain.cms.CmsTemplate;
import com.lxw.framework.domain.cms.request.QueryPageRequest;
import com.lxw.framework.domain.cms.response.CmsCode;
import com.lxw.framework.domain.cms.response.CmsPageResult;
import com.lxw.framework.domain.course.response.CoursePublishResult;
import com.lxw.framework.exception.ExceptionCast;
import com.lxw.framework.model.response.CommonCode;
import com.lxw.framework.model.response.QueryResponseResult;
import com.lxw.framework.model.response.QueryResult;
import com.lxw.framework.model.response.ResponseResult;
import com.lxw.manager.cms.config.RabbitConfig;
import com.lxw.manager.cms.dao.CmsPageRepository;
import com.lxw.manager.cms.dao.CmsSiteRepository;
import com.lxw.manager.cms.dao.CmsTemplateRepository;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Service
@Slf4j
public class CmsPageService {
    @Autowired
    private CmsPageRepository cmsPageRepository;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private CmsTemplateRepository cmsTemplateRepository;

    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private CmsSiteRepository cmsSiteRepository;

    @Autowired
    private  GridFSBucket gridFSBucket;


//      @Value("${yh.mq.routingKey}")
//      public String routingKey;

    public QueryResponseResult findCmsPages(Integer page,
                                            Integer size, QueryPageRequest queryPageRequest) {
        if (page <= 1) {
            page = 1;
        }
        page = page - 1;
        if (size < 1) {
            size = 10;
        }
        if (queryPageRequest == null) {
            queryPageRequest = new QueryPageRequest();
        }
        Pageable pageable = PageRequest.of(page, size);

        //存放查询条件的值对象
        CmsPage cmsPage = new CmsPage();
        //不为空的话，再去获取数据信息，也是避免出现空指针异常
        if (StringUtils.isNotBlank(queryPageRequest.getSiteId())) {
            cmsPage.setSiteId(queryPageRequest.getSiteId());
        }

        if (StringUtils.isNotBlank(queryPageRequest.getTemplateId())) {
            cmsPage.setTemplateId(queryPageRequest.getTemplateId());
        }
        //类似于获取ExampleMatcher对象
        ExampleMatcher exampleMatcher = ExampleMatcher.matching();
        if (StringUtils.isNotBlank(queryPageRequest.getPageAliase())) {
            cmsPage.setPageAliase(queryPageRequest.getPageAliase());
            //存放查询条件查询规则的
            exampleMatcher = ExampleMatcher.matching().withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains());
        }


        // where siteId='' and pageAliase like ''
        //第一个参数是实际cmsPage的参数，用与准确查询，后一个虽然也是一个
        // 实际数据，但是只用于模糊查询，空数据会自动忽略。
        Example<CmsPage> example = Example.of(cmsPage, exampleMatcher);
        //执行查询
        Page<CmsPage> all = cmsPageRepository.findAll(example, pageable);
        //创建一个新的容器接受查询到的数据QueryResult
        QueryResult<CmsPage> queryResult = new QueryResult(all.getContent(), all.getTotalElements());
        QueryResponseResult queryResponseResult = new QueryResponseResult(CommonCode.SUCCESS, queryResult);
        return queryResponseResult;
    }

    /**
     * 添加数据
     *
     * @param cmsPage 页面名称、别名、访问地址、类型（静态/动态）、页面模版、状态
     * @return CmsPageResult 包含cmsPage，及操作是否成功的信息
     */
    public CmsPageResult addCmsPage(CmsPage cmsPage) {
        //
        if (cmsPage == null) {
            cmsPage = new CmsPage();
        }
        CmsPage cmsPageDb = cmsPageRepository.findByPageNameAndPageWebPathAndSiteId(cmsPage.getPageName(),
                cmsPage.getPageWebPath(), cmsPage.getSiteId());
        //数据库中不存在该页面信息,进行添加
        if (cmsPageDb == null) {
            cmsPage.setPageId(null);
            cmsPageRepository.insert(cmsPage);
            return new CmsPageResult(CommonCode.SUCCESS, cmsPage);
        }
        //数据库存在该数据，就返回失败信息提示
        return new CmsPageResult(CommonCode.FAIL, null);
    }

    public CmsPageResult findCmsPageById(String id) {
        if (StringUtils.isEmpty(id)) {
            ExceptionCast.cast(CommonCode.INIT_PARAM);
        }
        Optional<CmsPage> optional = cmsPageRepository.findById(id);
        if (!optional.isPresent()) {
            ExceptionCast.cast(CmsCode.CMS_GET_PAGE_ID_ERROR);
        }

        CmsPage cmsPage = optional.get();
        CmsPageResult result = new CmsPageResult(CommonCode.SUCCESS, cmsPage);
        return result;

    }

    public CmsPageResult updateCmsPageById(String id, CmsPage cmsPage) {
        if (StringUtils.isEmpty(id)) {
            ExceptionCast.cast(CommonCode.INIT_PARAM);
//            CmsPageResult result = new CmsPageResult(CommonCode.INIT_PARAM,null);
//            return result;
        }
        if (cmsPage == null) {
            ExceptionCast.cast(CommonCode.INIT_PARAM);
        }
        Optional<CmsPage> optional = cmsPageRepository.findById(id);
        if (!optional.isPresent()) {
            ExceptionCast.cast(CommonCode.INIT_PARAM);
        }

        CmsPage one = optional.get();
        one.setTemplateId(cmsPage.getTemplateId());
        //更新所属站点
        one.setSiteId(cmsPage.getSiteId());
        //更新页面别名
        one.setPageAliase(cmsPage.getPageAliase());
        //更新页面名称
        one.setPageName(cmsPage.getPageName());
        //更新访问路径
        one.setPageWebPath(cmsPage.getPageWebPath());
        //更新物理路径
        one.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
        one.setDataUrl(cmsPage.getDataUrl());

        cmsPageRepository.save(one);

        CmsPageResult result = new CmsPageResult(CommonCode.SUCCESS, one);
        return result;


//        CmsPageResult result = new CmsPageResult(CommonCode.FAIL,null);
//        return result;
    }

    public ResponseResult deleteCmsPageById(String id) {
        if (StringUtils.isEmpty(id)) {
            return new ResponseResult(CommonCode.INIT_PARAM);
        }
        cmsPageRepository.deleteById(id);
        return new ResponseResult(CommonCode.SUCCESS);
    }

    public String gericHtml(String pageId) throws Exception {

        //根据pageId获取cmsPage信息
        CmsPageResult cmsPageResult = this.findCmsPageById(pageId);
        CmsPage cmsPage = cmsPageResult.getCmsPage();
        //根据dataUrl远程获取模板数据
        if (StringUtils.isEmpty(cmsPage.getDataUrl())) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAURLISNULL);
        }
        ResponseEntity<Map> entity = restTemplate.getForEntity(cmsPage.getDataUrl(), Map.class);
        Map body = entity.getBody();
        //获取模板信息
        String templateId = cmsPage.getTemplateId();
        Optional<CmsTemplate> optional = cmsTemplateRepository.findById(templateId);
        if (!optional.isPresent()) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        CmsTemplate cmsTemplate = optional.get();
        String file_id = cmsTemplate.getTemplateFileId();

//        InputStream inputStream = new FileUtils().getFileByIdMongDb(file_id);
        //根据文件id获取文件信息
        GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(file_id)));
        //通过gridFSBucket打开下载流
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
        GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
        InputStream inputStream = gridFsResource.getInputStream();
        String content = IOUtils.toString(inputStream, "utf-8");
        //生成静态html页面

        Configuration configuration = new Configuration(Configuration.getVersion());
        //
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template", content);
        configuration.setTemplateLoader(stringTemplateLoader);

        //通过Configuration获取模板信息
        Template template = configuration.getTemplate("template", "utf-8");
        System.out.println(template);
        String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, body);
        System.out.println(html);
        return html;
    }

    public ResponseResult postPage(String pageId) {
//获取生成的静态页面内容
        String html = "";
        try {
            html = this.gericHtml(pageId);
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }

        //把静态文件保存到gridFs,并更新MongoDB,cmsPage添加htmlFileId
        CmsPage cmsPage = this.uploadGfsAndUpdateCmsPage(pageId, html);
        //发送消息
        postCmsMessage(pageId, cmsPage);

        return new ResponseResult(CommonCode.SUCCESS);
    }

    private void postCmsMessage(String pageId, CmsPage cmsPage) {
        if (cmsPage == null) {
            ExceptionCast.cast(CmsCode.CMS_GET_PAGE_NULL_ERROR);
        }
        String siteId = cmsPage.getSiteId();
        Map<String, Object> map = new HashMap<>();
        map.put("pageId", pageId);
        String message = JSON.toJSONString(map);

        rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE_ROUTING, siteId, message);
    }

    private CmsPage uploadGfsAndUpdateCmsPage(String pageId, String html) {
        Optional<CmsPage> optionalCmsPage = cmsPageRepository.findById(pageId);
        if (!optionalCmsPage.isPresent()) {
            ExceptionCast.cast(CmsCode.CMS_GET_PAGE_NULL_ERROR);
        }
        CmsPage cmsPage = optionalCmsPage.get();
        String pageName = cmsPage.getPageName();
        String htmlFileId = cmsPage.getHtmlFileId();
        if (StringUtils.isNotEmpty(htmlFileId)) {
            gridFsTemplate.delete(Query.query(Criteria.where("_id").is(htmlFileId)));
        }
        try {
            InputStream inputStream = IOUtils.toInputStream(html, "utf-8");
            //上传文件
            ObjectId objectId = gridFsTemplate.store(inputStream, pageName);
            cmsPage.setHtmlFileId(objectId.toHexString());
            cmsPageRepository.save(cmsPage);
            return cmsPage;
        } catch (IOException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    public CmsPageResult saveCmsPage(CmsPage cmsPage) {
        CmsPage cmsPageDb = cmsPageRepository.findByPageNameAndPageWebPathAndSiteId(cmsPage.getPageName(),
                cmsPage.getPageWebPath(), cmsPage.getSiteId());
        //数据中不存在该页面信息,进行添加
        if (cmsPageDb == null) {
            cmsPage.setPageId(null);
            cmsPageRepository.insert(cmsPage);
            return new CmsPageResult(CommonCode.SUCCESS, cmsPage);
        } else {
            cmsPage.setPageId(cmsPageDb.getPageId());
            return this.updateCmsPageById(cmsPageDb.getPageId(), cmsPage);
        }
    }

    public CoursePublishResult postPageQuick(CmsPage cmsPage) {
        //添加或者更新cmsPage信息
        CmsPageResult result = this.saveCmsPage(cmsPage);
        if (!result.isSuccess()) {
            ExceptionCast.cast(CommonCode.FAIL);
        }
        String pageId = result.getCmsPage().getPageId();
        //发布页面
        CmsPage cmsPageDb = result.getCmsPage();
        cmsPageDb.setPageId(pageId);
        ResponseResult responseResult = this.postPage(pageId);
        if (!responseResult.isSuccess()) {
            ExceptionCast.cast(CommonCode.FAIL);
        }

        //根据站点id获取站点信息
        Optional<CmsSite> optionalCmsSite = cmsSiteRepository.findById(cmsPageDb.getSiteId());
        if (!optionalCmsSite.isPresent()) {
            ExceptionCast.cast(CommonCode.FAIL);
        }
        CmsSite cmsSite = optionalCmsSite.get();
        //拼接发布成功之后访问静态页面的路径
        String path = cmsSite.getSiteDomain() + cmsSite.getSiteWebPath() + cmsPageDb.getPageWebPath() + cmsPageDb.getPageName();
        CoursePublishResult coursePublishResult = new CoursePublishResult(CommonCode.SUCCESS, path);
        return coursePublishResult;
    }
}
